#include <esp_log.h>
#include <Arduino.h>
#include "OledTask.h"

#define SCL_OLED 15
#define SDA_OLED 4
#define RST_OLED 16

static const char TAG[] = "Oled";

OledTask::OledTask() : Task(TAG, 8192), _u8g2(NULL) {}

void OledTask::sleep() {
  if (_u8g2) {
    lock();
    _u8g2->setPowerSave(true);
    unlock();
    _bright = BRIGHT_OFF;
    _lastTime = 0;
  }
}

void OledTask::wakeup() {
  if (_u8g2) {
    lock();
    _u8g2->setPowerSave(false);
    _u8g2->setContrast(CONTRAST_NORMAL);
    unlock();
    _bright = BRIGHT_NORMAL;
    _lastTime = millis();
  }
}

void OledTask::setBrightness(brightness_t value) {
  if (_u8g2) {
    if (_bright != value) {
      lock();
      if (_bright == BRIGHT_OFF)
        _u8g2->setPowerSave(false);
      switch (value) {
        case BRIGHT_OFF:
          _u8g2->setPowerSave(true);
          _lastTime = 0;
          break;
        case BRIGHT_DIM:
          _u8g2->setContrast(CONTRAST_DIM);
          break;
        case BRIGHT_NORMAL:
          _u8g2->setContrast(CONTRAST_NORMAL);
          _lastTime = millis();
          break;
      }
      unlock();
      _bright = value;
    }
  }
}

void OledTask::setSymbols(uint8_t firstSymbol, uint8_t secondSymbol, uint8_t thirdSymbol, uint8_t fourthSymbol) {
  if (_u8g2) {
    notify(firstSymbol | (secondSymbol << 8) | (thirdSymbol << 16) | (fourthSymbol << 24));
  }
}

bool OledTask::initLocal() {
//  if (! Task::initLocal())
//    return false;

  _u8g2 = new U8G2_SSD1306_64X32_1F_F_HW_I2C(U8G2_R0, RST_OLED, SCL_OLED, SDA_OLED);
//  _u8g2 = new U8G2_SSD1306_64X32_1F_F_SW_I2C(U8G2_R0, SCL_OLED, SDA_OLED, RST_OLED);
  if (! _u8g2) {
    ESP_LOGE(TAG, "Error creating OLED object!");
    return false;
  }
  _u8g2->begin();
  _u8g2->setContrast(CONTRAST_NORMAL);
  _symbols = 0;
  _frames = 0;
  _bright = BRIGHT_NORMAL;
  _lastTime = millis();
  return true;
}

void OledTask::deinitLocal() {
  if (_u8g2) {
    _u8g2->setPowerSave(true);
    delete _u8g2;
    _u8g2 = NULL;
  }

//  Task::deinitLocal();
}

void OledTask::loop() {
  static const byte XBMS[8][128] = {
    {
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x00, 0xc0, 0x1f,
      0x00, 0x00, 0xe0, 0x3f, 0x00, 0x00, 0xf0, 0x7f, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0xfc, 0x3f,
      0x20, 0x00, 0xfe, 0x1f, 0x70, 0x00, 0xff, 0x0f, 0xf8, 0x80, 0xff, 0x07, 0xfc, 0xc1, 0xff, 0x03,
      0xfe, 0xe3, 0xff, 0x01, 0xff, 0xf7, 0xff, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xfc, 0xff, 0x3f, 0x00,
      0xf8, 0xff, 0x1f, 0x00, 0xf0, 0xff, 0x0f, 0x00, 0xe0, 0xff, 0x07, 0x00, 0xc0, 0xff, 0x03, 0x00,
      0x80, 0xff, 0x01, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00,
      0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
    {
      0x20, 0x00, 0x00, 0x02, 0x70, 0x00, 0x00, 0x07, 0xf8, 0x00, 0x80, 0x0f, 0xfc, 0x01, 0xc0, 0x1f,
      0xfe, 0x03, 0xe0, 0x3f, 0xff, 0x07, 0xf0, 0x7f, 0xfe, 0x0f, 0xf8, 0x7f, 0xfc, 0x1f, 0xfc, 0x3f,
      0xf8, 0x3f, 0xfe, 0x1f, 0xf0, 0x7f, 0xff, 0x0f, 0xe0, 0xff, 0xff, 0x07, 0xc0, 0xff, 0xff, 0x03,
      0x80, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0xfc, 0x3f, 0x00,
      0x00, 0xfe, 0x3f, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x80, 0xff, 0xff, 0x00, 0xc0, 0xff, 0xff, 0x01,
      0xe0, 0xff, 0xff, 0x03, 0xf0, 0xff, 0xff, 0x07, 0xf8, 0x7f, 0xfe, 0x0f, 0xfc, 0x3f, 0xfc, 0x1f,
      0xfe, 0x1f, 0xf8, 0x3f, 0xff, 0x0f, 0xf0, 0x7f, 0xfe, 0x07, 0xe0, 0x7f, 0xfc, 0x03, 0xc0, 0x3f,
      0xf8, 0x01, 0x80, 0x1f, 0xf0, 0x00, 0x00, 0x0f, 0x60, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00 },
    {
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00,
      0x00, 0x30, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00,
      0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x60, 0x00, 0x00, 0xfc, 0x60, 0x00, 0x00, 0xfe, 0xf1, 0x00,
      0x00, 0xfe, 0xf1, 0x00, 0x00, 0xfe, 0xf1, 0x01, 0x00, 0xfe, 0xfb, 0x01, 0xff, 0xcf, 0xfb, 0xff,
      0xff, 0xcf, 0xff, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0x87, 0xbf, 0xff, 0xe0, 0x87, 0x3f, 0x00,
      0xe0, 0x87, 0x1f, 0x00, 0xc0, 0x03, 0x1f, 0x00, 0xc0, 0x03, 0x0f, 0x00, 0xc0, 0x03, 0x0f, 0x00,
      0x80, 0x03, 0x06, 0x00, 0x80, 0x01, 0x06, 0x00, 0x80, 0x01, 0x06, 0x00, 0x80, 0x01, 0x02, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
    {
      0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0xc0, 0x1f, 0x00,
      0x00, 0xc0, 0x0f, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xf0, 0x0f, 0x00,
      0x00, 0xf0, 0x0f, 0x00, 0x00, 0xf0, 0x0f, 0x80, 0x00, 0xf0, 0x0f, 0xc0, 0x00, 0xf0, 0x0f, 0xe0,
      0x00, 0xf0, 0xff, 0xff, 0x00, 0xe0, 0xff, 0x7f, 0x00, 0xf0, 0xff, 0x7f, 0x00, 0xf8, 0xff, 0x3f,
      0x00, 0xfc, 0xff, 0x3f, 0x00, 0xfe, 0xff, 0x1f, 0x00, 0xff, 0xff, 0x07, 0x80, 0xff, 0xfb, 0x01,
      0xc0, 0xff, 0x01, 0x00, 0xe0, 0xff, 0x00, 0x00, 0xf0, 0x7f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00,
      0xfc, 0x1f, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0xe7, 0x07, 0x00, 0x00, 0xc3, 0x03, 0x00, 0x00,
      0xc3, 0x01, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00 },
    {
      0xf0, 0x01, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0xf0, 0xff, 0x03, 0x00,
      0x00, 0xfe, 0x07, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x7f, 0x00,
      0xf0, 0x00, 0xfc, 0x00, 0xf0, 0x0f, 0xf8, 0x01, 0xf0, 0x3f, 0xf0, 0x03, 0xf0, 0x7f, 0xe0, 0x07,
      0x00, 0xff, 0xc1, 0x07, 0x00, 0xf8, 0x83, 0x0f, 0x00, 0xe0, 0x07, 0x1f, 0x00, 0xc0, 0x0f, 0x1f,
      0x70, 0x80, 0x0f, 0x1e, 0xf0, 0x03, 0x1f, 0x3c, 0xf0, 0x07, 0x3e, 0x3c, 0xf0, 0x0f, 0x3c, 0x7c,
      0x80, 0x1f, 0x7c, 0x78, 0x00, 0x3e, 0x78, 0x78, 0x00, 0x7c, 0x78, 0x78, 0x00, 0x78, 0x78, 0xf0,
      0x3c, 0x78, 0xf0, 0xf0, 0x7e, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0xf0, 0xf0,
      0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00 },
    {
      0x00, 0xf0, 0x0f, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x80, 0xff, 0xff, 0x01, 0xc0, 0xff, 0xff, 0x03,
      0xe0, 0x1f, 0xf8, 0x07, 0xf0, 0x03, 0xc0, 0x0f, 0xf8, 0x01, 0x80, 0x1f, 0xfc, 0x00, 0x00, 0x3f,
      0x7c, 0xc0, 0x03, 0x3e, 0x3e, 0xc0, 0x03, 0x7c, 0x1e, 0xc0, 0x03, 0x78, 0x1e, 0xc0, 0x03, 0x78,
      0x1f, 0xc0, 0x03, 0xf8, 0x0f, 0xc0, 0x03, 0xf0, 0x0f, 0xc0, 0x03, 0xf0, 0x0f, 0xc0, 0x03, 0xf0,
      0x0f, 0xc0, 0x07, 0xf0, 0x0f, 0x80, 0x0f, 0xf0, 0x0f, 0x00, 0x0f, 0xf0, 0x1f, 0x00, 0x06, 0xf8,
      0x1e, 0x00, 0x00, 0x78, 0x1e, 0x00, 0x00, 0x78, 0x3e, 0x00, 0x00, 0x7c, 0x7c, 0x00, 0x00, 0x3e,
      0xfc, 0x00, 0x00, 0x3f, 0xf8, 0x01, 0x80, 0x1f, 0xf0, 0x03, 0xc0, 0x0f, 0xe0, 0x1f, 0xf8, 0x07,
      0xc0, 0xff, 0xff, 0x03, 0x80, 0xff, 0xff, 0x01, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0xf0, 0x0f, 0x00 },
    {
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x80, 0x1f, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0xf8, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x03,
      0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x0f,
      0xe0, 0xff, 0xff, 0x0f, 0xf8, 0xff, 0xff, 0x0f, 0xfc, 0xff, 0xff, 0x0f, 0xfe, 0xff, 0xff, 0x0f,
      0xfe, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f,
      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff,
      0xfe, 0xff, 0xff, 0x7f, 0xfc, 0xff, 0xff, 0x7f, 0xf8, 0xff, 0xff, 0x3f, 0xe0, 0xff, 0xff, 0x0f,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
    {
      0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00,
      0xf0, 0x03, 0x00, 0x00, 0xf8, 0x03, 0x00, 0x00, 0xf8, 0x03, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00,
      0xfe, 0x03, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00,
      0xff, 0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0x1f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00,
      0xff, 0x7f, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x07, 0x00,
      0xfe, 0xff, 0x3f, 0x40, 0xfe, 0xff, 0xff, 0x7f, 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f,
      0xf8, 0xff, 0xff, 0x1f, 0xf0, 0xff, 0xff, 0x0f, 0xe0, 0xff, 0xff, 0x07, 0xc0, 0xff, 0xff, 0x03,
      0x80, 0xff, 0xff, 0x01, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00 }
  };

  uint32_t notifyValue;
  uint8_t symbol;
  bool blink;
  bool redraw = false;

  if (waitNotify(notifyValue, 500)) {
    setBrightness(BRIGHT_NORMAL);
    _symbols = notifyValue;
    _frames = 0;
    redraw = true;
  }
  if (_lastTime) {
    if (millis() - _lastTime >= DIM_TIMEOUT + OFF_TIMEOUT)
      setBrightness(BRIGHT_OFF);
    else if (millis() - _lastTime >= DIM_TIMEOUT)
      setBrightness(BRIGHT_DIM);
  }
  if (! redraw) {
    redraw = (_bright > BRIGHT_OFF) && ((_symbols & (SYMBOL_BLINK | (SYMBOL_BLINK << 8) | (SYMBOL_BLINK << 16) | (SYMBOL_BLINK << 24))) != 0);
  }
  if (redraw) {
    lock();
    _u8g2->clearBuffer();
    for (uint8_t i = 0; i < _u8g2->getWidth() / 32; ++i) {
      symbol = (_symbols >> (i * 8)) & 0xFF;
      blink = symbol & SYMBOL_BLINK;
      symbol &= ~SYMBOL_BLINK;
      if ((symbol != SYMBOL_NONE) && ((! blink) || (! (_frames & 0x01)))) {
        _u8g2->drawXBMP(i * 32, 0, 32, 32, XBMS[symbol - 1]);
      }
    }
    _u8g2->sendBuffer();
    unlock();
  }
  ++_frames;
}
